package geom

import "github.com/hajimehoshi/ebiten/v2"

type Collider interface {
	Contains(point Point) bool
}

type ColliderPoint struct {
	Pivot Point
}

func (c *ColliderPoint) Contains(point Point) bool {
	return c.Pivot == point
}

func NewColliderCircle(pivot Point, radius float64) *ColliderCircle {
	return &ColliderCircle{
		ColliderPoint: ColliderPoint{
			Pivot: pivot,
		},
		Radius: radius,
	}
}

type ColliderCircle struct {
	ColliderPoint
	Radius float64
}

func (c *ColliderCircle) Contains(point Point) bool {
	return c.Pivot.AsVec2().Sub(point.AsVec2()).Length() <= c.Radius
}

func NewColliderRectangle(pivot Point, size Size) *ColliderRectangle {
	return &ColliderRectangle{
		ColliderPoint: ColliderPoint{
			Pivot: pivot,
		},
		Size: size,
	}
}

type ColliderRectangle struct {
	ColliderPoint
	Size Size
}

func (c *ColliderRectangle) Contains(point Point) bool {
	p := point.AsVec2().Sub(c.Pivot.AsVec2())
	return p.X >= 0 && p.X <= c.Size.Width && p.Y >= 0 && p.Y <= c.Size.Height
}

func NewColliderTriangle(pivot Point, a, b, c Point) *ColliderTriangle {
	return &ColliderTriangle{
		ColliderPoint: ColliderPoint{
			Pivot: pivot,
		},
		A: a,
		B: b,
		C: c,
	}
}

type ColliderTriangle struct {
	ColliderPoint
	A, B, C Point
}

func (c *ColliderTriangle) Contains(point Point) bool {
	p := point.AsVec2().Sub(c.Pivot.AsVec2()).AsPoint()
	st := triangleDoubleSquare(c.A, c.B, c.C)
	if st == 0 {
		return false
	}
	s1 := triangleDoubleSquare(p, c.A, c.C)
	if s1 == 0 {
		return true
	}
	s2 := triangleDoubleSquare(p, c.A, c.B)
	if s2 == 0 {
		return true
	}
	s3 := triangleDoubleSquare(p, c.B, c.C)
	if s3 == 0 {
		return true
	}
	return st == s1+s2+s3
}

type ColliderSet struct {
	colliders []Collider
}

func NewColliderSet(colliders ...Collider) *ColliderSet {
	return &ColliderSet{
		colliders: colliders,
	}
}

func (c *ColliderSet) AddCollider(collider Collider) {
	c.colliders = append(c.colliders, collider)
}

func (c *ColliderSet) Contains(point Point) bool {
	for _, collider := range c.colliders {
		if collider.Contains(point) {
			return true
		}
	}
	return false
}

func (c *ColliderSet) GetColliders() []Collider {
	return c.colliders
}

func MakeTrianglesCollider(vs []ebiten.Vertex, is []uint16) Collider {
	c := &ColliderSet{}
	if len(vs) == 0 {
		return &ColliderPoint{}
	}
	pivot := NewVec2FromF32(vs[0].DstX, vs[0].DstY)
	for i := 0; i < len(is); i += 3 {
		ct := NewColliderTriangle(
			pivot.AsPoint(),
			NewVec2FromF32(vs[is[i]].DstX, vs[is[i]].DstY).Sub(pivot).AsPoint(),
			NewVec2FromF32(vs[is[i+1]].DstX, vs[is[i+1]].DstY).Sub(pivot).AsPoint(),
			NewVec2FromF32(vs[is[i+2]].DstX, vs[is[i+2]].DstY).Sub(pivot).AsPoint(),
		)
		c.AddCollider(ct)
	}

	return c
}
